#ifndef COLOR_H
#define COLOR_H

enum ColorName
{
  black,
  red,
  green,
  brown,
  blue,
  magenta,
  cyan,
  lightgray,

  darkgray,
  lightred,
  lightgreen,
  yellow,
  lightblue,
  lightmagenta,
  lightcyan,
  white
};

// black = 0 
// red = FOREGROUND_RED
// green = FOREGROUND_GREEN
// blue = FOREGROUND_BLUE
// brown = FOREGROUND_RED | FOREGROUND_GREEN
// magenta = FOREGROUND_RED | FOREGROUND_BLUE
// cyan = FOREGROUND_GREEN | FOREGROUND_BLUE
// lightgray = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
// 
// if color > lightgray  
// output |= FOREGROUND_INTENSITY
// color -= darkgray
#ifdef WIN32
inline WORD win32Color(ColorName name)
{
  switch(name)
  {
    case black:
      return 0;
    case red:
      return FOREGROUND_RED;
    case green: 
      return FOREGROUND_GREEN;
    case blue:
      return FOREGROUND_BLUE;
    case brown:
      return FOREGROUND_RED | FOREGROUND_GREEN;
    case magenta:
      return FOREGROUND_RED | FOREGROUND_BLUE;
    case cyan:
      return FOREGROUND_GREEN | FOREGROUND_BLUE;
    case lightgray:
      return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
    default:
      return convertColor(name - darkgray) | FOREGROUND_INTENSITY;
  }
}
#endif
//const ColorName colors[] = { black, red, green, brown, blue, magenta, cyan, lightgray, darkgray,
//                             lightred, lightgreen, yellow, lightblue, lightmagenta, lightcyan, white };

struct Color
{
  Color(ColorName f = white, ColorName b = black): fore(f), back(b) {}

  ColorName fore;
  ColorName back;
};


inline ostream& operator<<(ostream& o, const Color& c)
{
  #ifdef WIN32
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), win32Color(c.fore) | (win32Color(c.back) << 4 ));
  return o;
  #else
  if(c.fore > lightgray) // bold color
    o << "\033[1;3" << c.fore - lightgray - 1 << "m";
  else
    o << "\033[0;3" << c.fore << "m";

  return o << "\033[4" << c.back << "m";
  #endif
}


struct gotoxy
{
  gotoxy(int x_, int y_): x(x_), y(y_) {}
  int x;
  int y;
};

inline ostream& operator<<(ostream& o, const gotoxy& g)
{
  #ifdef WIN32
  COORD coord = {g.x, g.y};
  SetConsoleCursorPosition ( GetStdHandle ( STD_OUTPUT_HANDLE ), coord );
  return o;
  #else
  return o << "\033[" << g.y << ";" << g.x << "f";
  #endif
}

struct Clear 
{
  Clear() {};
};

inline ostream& operator<<(ostream& o, const Clear& c)
{
  #ifdef WIN32
  system("cls");
  return o;
  #else
  const char clearScreenEscapeSequence[] = "\E[H\E[2J";
  return o << clearScreenEscapeSequence;
  #endif
}

#endif